package msu.ml.tools.birdminer;

import org.w3c.dom.*;
import msu.ml.util.*;
import msu.ml.data.*;
import weka.classifiers.*;
import weka.core.*;


public class PassiveExperiment
{
   private Classifier classifier;
   private ISweepProvider sweepProvider;
   private ISweepClassifier sweepClassifier;

   public Classifier getClassifier()
   {
      return this.classifier;
   }

   public ISweepProvider getSweepProvider()
   {
      return this.sweepProvider;
   }

   public ISweepClassifier getSweepClassifier()
   {
      return this.sweepClassifier;
   }

   public static PassiveExperiment parse(String file)
   {
      NodeList list = XmlUtility.xPathQuery(file, 
         "/experiment/process_unclassified_data");
      if(list.getLength() > 0)
      {
         PassiveExperiment experiment = new PassiveExperiment();
         experiment.parseExperiment((Element)(list.item(0)));
         return experiment;
      }

      return null;
   }

   public void parseExperiment(Element root)
   {
      this.sweepProvider = parseSweeps(
         XmlUtility.getSingleElement(root, "sweeps"));

      this.classifier = parseClassifier(
         XmlUtility.getSingleElement(root, "classifier"));

      this.sweepClassifier = parseSweepClassifier(
         XmlUtility.getSingleElement(root, "sweep_classifier"));
   }

   private static IDataSource parseSource(Element source)
   {
      String order = "";
      int limit = 0;

      if(source.hasAttribute("order"))
         order = source.getAttribute("order");

      if(source.hasAttribute("limit"))
      {
         try
         {
            limit = Integer.parseInt(source.getAttribute("limit"));
         }
         catch(Exception e)
         {
            System.out.println(e);
         }
      }

      Node features = XmlUtility.getSingleNode(source, "features");
      String [] indices = new String[0];
      if(features != null)
         indices = (features.getTextContent()).split(",");

      Element db = XmlUtility.getSingleElement(source, "database");
      if(db != null)
      {
         FilteredPulseVolumeSQLAdapter adapter = 
            new FilteredPulseVolumeSQLAdapter(0);
         adapter.includeFeature(FilteredPulseVolumeSQLAdapter.NONE);
         for(int i = 0; i < indices.length; i++)
         {
            try
            {
               adapter.includeFeature(Integer.parseInt(indices[i].trim()));
            }
            catch(Exception e)
            {
               System.out.println(e.getMessage());
            }
         }

         adapter.includeFeature(FilteredPulseVolumeSQLAdapter.CLASS);
         String dbUrl = "jdbc:mysql://localhost/" + db.getAttribute("name");
         String dbUser = db.getAttribute("user");
         return new DatabaseDataSource(new DatabaseModel(dbUrl, dbUser, ""),
            adapter, limit, order.equals("random"));
      }

      return null;
   }

   private static ISweepProvider parseSweeps(Element sweeps)
   {
      IDataSource source = parseSource(XmlUtility.getSingleElement(
         sweeps, "source"));
      String select = sweeps.getAttribute("select");
      if(select.equals("manual"))
      {
         ManualSweepProvider provider = new ManualSweepProvider(source);
         NodeList list = sweeps.getElementsByTagName("sweep");
         for(int i = 0; i < list.getLength(); i++)
         {
            Element e = (Element)(list.item(i));
            provider.addSweep(e.getAttribute("volume"));
         }
         return provider;
      }
      else if(select.equals("auto"))
      {
         return new AutoSweepProvider(source);
      }

      return null;
   }

   private static Classifier parseClassifier(Element classifier)
   {
      String path = classifier.getAttribute("path");

      try
      {
         return (Classifier)weka.core.SerializationHelper.read(path);
      }
      catch(Exception e){}

      return null;
   }

   private static ISweepClassifier parseSweepClassifier(Element rule)
   {
      Element threshold = XmlUtility.getSingleElement(rule, "threshold");
      if(threshold != null)
      {
         try
         {
            double value = Double.parseDouble(threshold.getAttribute("value"));
            int target = Integer.parseInt(threshold.getAttribute("target"));
            return new ThresholdSweepClassifier(value, target);
         }
         catch(Exception e){}
      }

      return null;
   }
}
